home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * libsample -
- * read and write samples of sound.
- *
- * exports:
- * sample *readsample(name);
- * writesample(s,name);
- *
- * printsample(s);
- *
- * playsample(s);
- * playsubsample(s,start,finish);
- * flushsample();
- *
- * expandsample(s);
- * minmaxsample(s,min,max);
- * scalesample(s,gain);
- * stereoizesample(s,mag);
- *
- * freesample(s);
- * sample *clonesample(s);
- *
- * sample *tonesample(nsamples);
- * sample *subsample(s,begin,end);
- * sample *extendsample(s,len);
- * reversesample(s);
- *
- * beginnotes();
- * playnote(s,ftime,amplitude);
- * endnotes();
- * setbpm(b)
- * flushnotes(ftime)
- * sethumanize(time,amp)
- *
- * Paul Haeberli - 1991
- */
- #include "math.h"
- #include "stdio.h"
- #include "fcntl.h"
- #include "sys/types.h"
- #include "malloc.h"
- #include "aiff.h"
- #include "audio.h"
- #include "sample.h"
-
- int ilimit(min,v,max)
- int min,v,max;
- {
- if(v<min)
- return min;
- if(v>max)
- return max;
- return v;
- }
-
- /*
- * code to READ an aiff file
- *
- *
- */
- static void
- copy_audio_samps(ssnd_chunk_t *ssnd_data,
- audio_params_t *audio_params,
- sample *s);
-
- typedef union
- {
- unsigned char b[2];
- short s;
- } align_short_t;
-
- typedef union
- {
- unsigned char b[4];
- long l;
- } align_long_t;
-
- /*
- * local subroutines
- */
- void parse_cmd_line(int argc, char **argv);
- static int read_chunk_header(chunk_header_t *);
- static void read_form_chunk(chunk_header_t *, form_chunk_t *);
- static void read_comm_chunk(chunk_header_t *,comm_chunk_t *,
- audio_params_t *audio_params);
- static void read_ssnd_chunk(chunk_header_t *, ssnd_chunk_t *);
- static void skip_chunk(chunk_header_t *);
-
- /*
- * globals
- */
- static char *filename; /* input file name */
- static int fd; /* input file descriptor */
- static char *myname; /* name of this program */
- static long bytes_per_samp;
- static long samps_per_frame;
- static long frames_per_sec;
- static long total_frames;
- static long total_samps;
- static long total_samp_bytes;
- static long total_bytes; /* total bytes in output file */
-
- sample *readsample(name)
- char *name;
- {
- int i,n;
- char buf[8];
- chunk_header_t chunk_header;
- form_chunk_t form_data;
- comm_chunk_t comm_data;
- ssnd_chunk_t ssnd_data;
- audio_params_t audio_params;
- ALport audio_port;
- sample *s;
-
- myname = "readaiff";
- filename = name;
-
- if ((fd = open(filename, O_RDONLY)) < 0) {
- fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
- exit(-1);
- }
-
- if ((n = read_chunk_header(&chunk_header)) != CHUNK_HEADER) {
- fprintf(stderr, "%s: failed to read FORM chunk header\n", myname);
- exit(-1);
- }
- if (strncmp(chunk_header.id, "FORM", 4)) { /* form container */
- fprintf(stderr, "%s: couldn't find FORM chunk id\n", myname);
- exit(-1);
- }
- read_form_chunk(&chunk_header, &form_data);
-
- /*
- * loop on the local chunks
- */
- while (1) {
- if ((n = read_chunk_header(&chunk_header)) == 0)
- goto loop_done;
- else if (n != CHUNK_HEADER) {
- fprintf(stderr, "%s: failed to read a chunk header\n", myname);
- exit(-1);
- }
- if (!strncmp(chunk_header.id, "COMM", 4)) /* common */
- read_comm_chunk(&chunk_header, &comm_data, &audio_params);
- else if (!strncmp(chunk_header.id, "SSND", 4)) /* sound data */
- read_ssnd_chunk(&chunk_header, &ssnd_data);
- else if ((!strncmp(chunk_header.id, "MARK", 4)) /* marker */
- || (!strncmp(chunk_header.id, "INST", 4)) /* instrument */
- || (!strncmp(chunk_header.id, "APPL", 4)) /* appl specific */
- || (!strncmp(chunk_header.id, "MIDI", 4)) /* midi data */
- || (!strncmp(chunk_header.id, "AESD", 4)) /* audio rec */
- || (!strncmp(chunk_header.id, "COMT", 4)) /* comments */
- || (!strncmp(chunk_header.id, "NAME", 4)) /* text */
- || (!strncmp(chunk_header.id, "AUTH", 4)) /* text */
- || (!strncmp(chunk_header.id, "(c) ", 4)) /* text */
- || (!strncmp(chunk_header.id, "ANNO", 4))) { /* text */
- skip_chunk(&chunk_header);
- } else {
- fprintf(stderr,
- "%s: bad chunk id 0x%02x%02x%02x%02x\n",
- myname, chunk_header.id[0],chunk_header.id[1],
- chunk_header.id[2], chunk_header.id[3]);
- }
- } /* while */
-
- loop_done:
-
- s = (sample *)malloc(sizeof(struct sample));
- /*
- * save the sample data
- */
- s->samprate = audio_params.samprate;
- s->sampwidth = audio_params.sampwidth;
- s->nchannels = audio_params.nchannels;
- if(s->sampwidth != 2) {
- fprintf(stderr,"samplewidth must be 2 bytes for now\n");
- exit(1);
- }
- if(s->nchannels != 2) {
- fprintf(stderr,"nchannels must be 2 (stereo) for now\n");
- exit(1);
- }
- copy_audio_samps(&ssnd_data, &audio_params, s);
- close(fd);
- return s;
- }
-
- /*
- * R E A D _ C H U N K _ H E A D E R
- */
- static int
- read_chunk_header(chunk_header_t *chunk_header)
- {
- align_long_t align_long;
- char buf[CHUNK_HEADER];
- int i, n;
-
- if ((n = read(fd, buf, CHUNK_HEADER)) != CHUNK_HEADER)
- return(n);
- for (i=0; i<4; i++)
- chunk_header->id[i] = buf[i];
- for (i=0; i<4; i++)
- align_long.b[i] = buf[i+4];
- chunk_header->size = align_long.l;
- return(CHUNK_HEADER);
- }
-
- static void
- read_form_chunk(chunk_header_t *chunk_header, form_chunk_t *form_data)
- {
- int n;
- char buf[FORM_CHUNK_DATA];
-
- if (chunk_header->size < 0) {
- fprintf(stderr, "%s: invalid FORM chunk data size %d\n",myname,
- chunk_header->size);
- exit(-1);
- } else if (chunk_header->size == 0) {
- fprintf(stderr,"%s: FORM chunk data size = 0\n", myname);
- exit(0);
- }
- if ((n = read(fd, buf, FORM_CHUNK_DATA)) != FORM_CHUNK_DATA) {
- fprintf(stderr, "%s: couldn't read AIFF identifier from %s\n",
- myname, filename);
- exit(-1);
- }
- if (strncmp(buf, "AIFF", 4)) {
- fprintf(stderr, "%s: %s does not have an AIFF identifier\n",
- myname, filename);
- exit(-1);
- }
- }
-
-
- /*
- * R E A D _ C O M M _ C H U N K
- */
- static void
- read_comm_chunk(chunk_header_t *chunk_header,
- comm_chunk_t *comm_data,
- audio_params_t *audio_params)
- {
- int n;
- char *buf, *bufp;
- int i;
- align_short_t align_short;
- align_long_t align_long;
-
- buf = malloc(COMM_CHUNK_DATA + 1); /* one extra loc at the end */
-
- if ((n = read(fd, buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA) {
- fprintf(stderr,
- "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
- myname, COMM_CHUNK_DATA, n);
- exit(-1);
- }
- bufp = buf;
- for (i=0; i<2; i++)
- align_short.b[i] = *bufp++;
- comm_data->nchannels = align_short.s;
- for (i=0; i<4; i++)
- align_long.b[i] = *bufp++;
- comm_data->nsampframes = align_long.l;
- for (i=0; i<2; i++)
- align_short.b[i] = *bufp++;
- comm_data->sampwidth = align_short.s;
- /*
- * the sample rate value from the common chunk is an 80-bit IEEE extended
- * floating point number:
- * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
- *
- * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
- * and cast them as an integer: the integer value equals the sample rate
- */
- for (i=0; i<2; i++)
- bufp++;
- align_short.b[0] = *bufp++;
- align_short.b[1] = *bufp++;
- for (i=0; i<6; i++)
- bufp++;
- comm_data->samprate = (unsigned short)align_short.s;
-
- switch (comm_data->samprate) {
- case 48000:
- audio_params->samprate = AL_RATE_48000;
- break;
- case 44100:
- audio_params->samprate = AL_RATE_44100;
- break;
- case 32000:
- audio_params->samprate = AL_RATE_32000;
- break;
- case 16000:
- audio_params->samprate = AL_RATE_16000;
- break;
- case 8000:
- audio_params->samprate = AL_RATE_8000;
- break;
- default:
- fprintf(stderr,"%s: can't set output sample rate to %d\n",
- myname, audio_params->samprate);
- audio_params->samprate = AL_RATE_48000;
- }
- switch (comm_data->nchannels) {
- case 1:
- audio_params->nchannels = AL_MONO;
- break;
- case 2:
- audio_params->nchannels = AL_STEREO;
- break;
- default:
- fprintf(stderr, "%s: can't handle %d channels per frame\n",
- myname, comm_data->nchannels);
- audio_params->nchannels = AL_STEREO;
- }
- switch (comm_data->sampwidth) {
- case 8:
- audio_params->sampwidth = AL_SAMPLE_8;
- break;
- case 16:
- audio_params->sampwidth = AL_SAMPLE_16;
- break;
- case 24:
- audio_params->sampwidth = AL_SAMPLE_24;
- break;
- default:
- fprintf(stderr, "%s: unsupported sample width %d bits\n",
- myname, comm_data->nchannels);
- audio_params->sampwidth = AL_SAMPLE_16;
- }
- free(buf);
- }
-
- static void
- read_ssnd_chunk(chunk_header_t *chunk_header, ssnd_chunk_t *ssnd_data)
- {
- char buf[SSND_CHUNK_DATA];
- int i;
- align_long_t align_long;
-
- read(fd, buf, SSND_CHUNK_DATA);
- for (i=0; i<4; i++)
- align_long.b[i] = buf[i];
- ssnd_data->offset = align_long.l;
- for (i=0; i<4; i++)
- align_long.b[i] = buf[i+4];
- ssnd_data->blocksize = align_long.l;
- /*
- * store the offset to the beginning of the audio sample data so that
- * we can come back and play it later
- */
- ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
- ssnd_data->sample_bytes = chunk_header->size - 2*sizeof(long);
-
- /*
- * move the fileptr to the end of the chunk
- */
- lseek(fd, ssnd_data->sample_bytes, SEEK_CUR);
- }
-
-
- /*
- * COPY_AUDIO_SAMPS
- */
- static void
- copy_audio_samps(ssnd_chunk_t *ssnd_data,
- audio_params_t *audio_params,
- sample *s)
- {
- int num_bufs;
- int leftover_bytes;
- int leftover_samps;
- int leftover_frames;
- int nread;
- int bytes_per_buf;
- int samps_per_buf;
- int samp_count;
- int frame_count;
- int frames_per_buf;
- float secs_per_frame;
- float secs_per_buf;
- float sec_count;
- int i;
- char *sampbuf;
-
- /*
- * decide what size blocks of samples we should read from the
- * AIFF file and pass to ALwritesamps
- */
- switch (audio_params->sampwidth) {
- case AL_SAMPLE_8:
- bytes_per_samp = 1;
- break;
- case AL_SAMPLE_16:
- default:
- bytes_per_samp = 2;
- break;
- }
- switch (audio_params->nchannels) {
- case AL_MONO:
- samps_per_frame = 1;
- break;
- case AL_STEREO:
- default:
- samps_per_frame = 2;
- break;
- }
- switch(audio_params->samprate) {
- case AL_RATE_48000: frames_per_sec = 48000; break;
- case AL_RATE_44100: frames_per_sec = 44100; break;
- case AL_RATE_32000: frames_per_sec = 32000; break;
- case AL_RATE_16000: frames_per_sec = 16000; break;
- case AL_RATE_8000: frames_per_sec = 8000; break;
- }
- /*
- * make the buffer large enough to hold 1/2 sec of audio frames
- */
- secs_per_frame = 1.0 / ((float)frames_per_sec);
- bytes_per_buf = bytes_per_samp * samps_per_frame * frames_per_sec / 2;
- samps_per_buf = bytes_per_buf / bytes_per_samp;
- frames_per_buf = samps_per_buf / samps_per_frame;
- secs_per_buf = secs_per_frame * frames_per_buf;
- sampbuf = malloc(bytes_per_buf);
-
- /*
- * figure out how many reads we have to do
- */
- total_samp_bytes = ssnd_data->sample_bytes;
- total_samps = total_samp_bytes / bytes_per_samp;
- total_frames = total_samps / samps_per_frame;
- num_bufs = total_samp_bytes / bytes_per_buf;
- leftover_bytes = total_samp_bytes % bytes_per_buf;
- leftover_samps = leftover_bytes / bytes_per_samp;
- leftover_frames = leftover_samps / samps_per_frame;
-
- /*
- * move the fileptr to the beginning of the sample data
- */
- lseek(fd, ssnd_data->file_position, SEEK_SET);
- s->nsamples = total_samps;
- s->data = (short *)malloc(total_samp_bytes);
- read(fd, s->data, total_samp_bytes);
- }
-
- /*
- * S K I P _ C H U N K
- */
- static void
- skip_chunk(chunk_header_t *chunk_header)
- {
- lseek(fd, chunk_header->size, SEEK_CUR);
- }
-
- /*
- * Stuff to WRITE an aiff file
- *
- */
-
- /*
- * local subroutines
- */
- static void write_form_chunk(form_chunk_t *);
- static void write_comm_chunk(comm_chunk_t *, sample *);
- static void write_ssnd_chunk(ssnd_chunk_t *);
- static void write_audio(sample *s);
- static void update_form_chunk(form_chunk_t *);
- static void update_comm_chunk(comm_chunk_t *);
- static void update_ssnd_chunk(ssnd_chunk_t *);
-
- writesample(s,name)
- sample *s;
- char *name;
- {
- int i,n;
- form_chunk_t form_chunk;
- comm_chunk_t comm_chunk;
- ssnd_chunk_t ssnd_chunk;
-
- myname = "writesample";
- filename = name;
- if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
- fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
- exit(-1);
- }
- write_form_chunk(&form_chunk);
- write_comm_chunk(&comm_chunk, s);
- write_ssnd_chunk(&ssnd_chunk);
- write_audio(s);
- total_bytes = FORM_CHUNK + COMM_CHUNK + SSND_CHUNK + total_samp_bytes;
- update_form_chunk(&form_chunk);
- update_comm_chunk(&comm_chunk);
- update_ssnd_chunk(&ssnd_chunk);
- close(fd);
- }
-
- /*
- * W R I T E _ F O R M _ C H U N K
- */
- static void
- write_form_chunk(form_chunk_t *form_chunk)
- {
- char buf[FORM_CHUNK];
-
- bzero(buf,FORM_CHUNK);
- bcopy("FORM",buf,4);
- bcopy("AIFF",buf+8,4);
- write(fd,buf,FORM_CHUNK);
- form_chunk->file_position = 0;
- }
-
- /*
- * W R I T E _ C O M M _ C H U N K
- */
- static void
- write_comm_chunk(comm_chunk_t *comm_chunk, sample *s)
- {
- char buf[COMM_CHUNK];
- int i;
- char *bufp, *cp;
- long tmplong;
- short tmpshort;
-
- /*
- * here is the structure of a COMM_CHUNK:
- *
- * 0 char[4] const "COMM"
- * 4 long const COMM_CHUNK_DATA
- * 8 short n channels
- * 10 long n sample frames
- * 14 short sample width
- * 16 char[10] 80 bit floating point sample rate
- */
- bzero(buf,COMM_CHUNK);
- bcopy("COMM",buf,4); /* char[4] chunk id */
- tmplong = COMM_CHUNK_DATA;
- bcopy(&tmplong,buf+4,sizeof(long)); /* long COMM_CHUNK_DATA */
- tmpshort = s->nchannels;
- bcopy(&tmpshort,buf+8,sizeof(short)); /* short nchannels */
- tmplong = 0; /* gets written later */
- bcopy(&tmplong,buf+10,sizeof(long)); /* long sampleframes (later) */
- tmpshort = 8*s->sampwidth;
- bcopy(&tmpshort,buf+14,sizeof(short)); /* short sampwidth */
- tmpshort = s->samprate;
- cp = (char *)&tmpshort; /* 10-bit extended samprate*/
- bufp = buf+16;
- /*
- * WOW!! this works: 80 bit floating point number follows
- */
- *bufp++ = 0x40;
- *bufp++ = 0x0e;
- *bufp++ = *cp++;
- *bufp++ = *cp;
- /* the rest is already zero!! */
-
- comm_chunk->file_position = lseek(fd, 0, SEEK_CUR);
- write(fd, buf, COMM_CHUNK);
- }
-
- /*
- * W R I T E _ S S N D _ C H U N K
- */
- static void
- write_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
- {
- char buf[SSND_CHUNK];
-
- bzero(buf,SSND_CHUNK);
- bcopy("SSND",buf,4);
- ssnd_chunk->file_position = lseek(fd, 0, SEEK_CUR);
- write(fd, buf, SSND_CHUNK);
- }
-
- /*
- * save_audio
- */
- static void
- write_audio(sample *s)
- {
- int nbytes;
- unsigned char *buf;
- int samps_per_buf;
- int bytes_per_buf;
- int frames_per_buf;
- int frames_per_sec;
- int bytes_per_samp;
- int samps_per_frame;
- int togo, thistime;
-
- bytes_per_samp = 2; /* hardwire to 16-bit samples */
- samps_per_frame = 2; /* hardwire to stereo */
- frames_per_sec = ((float)s->samprate);
- frames_per_buf = frames_per_sec / 2;
- samps_per_buf = frames_per_buf * samps_per_frame;
- bytes_per_buf = samps_per_buf * bytes_per_samp;
- total_frames = 0;
- total_samp_bytes = 0;
-
- /*
- * we assume the file pointer now points to the beginning
- * of the audio sample section of the AIFF file
- */
- togo = s->nsamples*s->sampwidth;
- buf = (unsigned char *)s->data;
- while(togo) {
- thistime = bytes_per_buf;
- if(thistime>togo)
- thistime = togo;
- if ((nbytes = write(fd, buf, thistime)) != thistime) {
- fprintf(stderr,
- "%s: tried to write %d bytes to %s, actually wrote %d\n",
- myname, thistime, filename, nbytes);
- exit(1);
- }
- buf += thistime;
- total_frames += (nbytes/(samps_per_frame*bytes_per_samp));
- total_samp_bytes += nbytes;
- togo -= thistime;
- }
- }
-
- /*
- * U P D A T E _ F O R M _ C H U N K
- */
- static void
- update_form_chunk(form_chunk_t *form_chunk)
- {
- long seekpos;
-
- seekpos = form_chunk->file_position + 4; /* seek past 4 id bytes */
- lseek(fd, seekpos, SEEK_SET);
- writelong(fd,total_bytes-CHUNK_HEADER);
- }
-
- /*
- * U P D A T E _ C O M M _ C H U N K
- */
- static void
- update_comm_chunk(comm_chunk_t *comm_chunk)
- {
- long seekpos;
-
- seekpos = comm_chunk->file_position + CHUNK_HEADER + sizeof(short);
- lseek(fd, seekpos, SEEK_SET);
- writelong(fd,total_frames);
-
- }
-
- /*
- * U P D A T E _ S S N D _ C H U N K
- */
- static void
- update_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
- {
- long seekpos;
-
- seekpos = ssnd_chunk->file_position + CHUNK_ID;
- lseek(fd, seekpos, SEEK_SET);
- writelong(fd,SSND_CHUNK_DATA + total_samp_bytes);
- }
-
- writelong(fd,val)
- int fd;
- long val;
- {
- write(fd, &val, sizeof(long));
- }
-
- /*
- * ulitity functions follow
- *
- */
- static int firsted;
- static ALport audioport;
-
- static writeaudio(data,nshorts,samprate)
- short *data;
- int nshorts, samprate;
- {
- long pvbuf[2];
- ALconfig portconfig;
-
- if(!firsted) {
- pvbuf[0] = AL_OUTPUT_RATE;
- pvbuf[1] = samprate;
- ALsetparams(AL_DEFAULT_DEVICE,pvbuf,2);
- portconfig = ALnewconfig();
- ALsetwidth(portconfig,2);
- ALsetchannels(portconfig,2);
- audioport = ALopenport("name","w",portconfig);
- firsted = 1;
- }
- if(!nshorts)
- return;
- ALwritesamps(audioport,data,nshorts);
- }
-
- playsample(s)
- sample *s;
- {
- playsubsample(s,0,s->nsamples-1);
- }
-
- playsubsample(s,start,finish)
- sample *s;
- {
- start = ilimit(0,start,s->nsamples-1);
- finish = ilimit(0,finish,s->nsamples-1);
- start &= 0xffffffe;
- finish &= 0xffffffe;
- writeaudio(s->data+start,finish-start+1,s->samprate);
- }
-
- flushsample()
- {
- if(firsted) {
- while(ALgetfilled(audioport) > 0)
- sginap(1);
- }
- }
-
- printsample(s)
- sample *s;
- {
- int min, max;
-
- printf("\nsample rate: %d\n",s->samprate);
- printf(" n channels: %d\n",s->nchannels);
- printf(" samp width: %d\n",s->sampwidth);
- printf(" n samples : %d\n",s->nsamples);
- minmaxsample(s,&min,&max);
- printf(" min val: %d\n",min);
- printf(" max val: %d\n",max);
- }
-
- expandsample(s)
- sample *s;
- {
- int min, max, del;
- int n;
- short *sptr;
-
- minmaxsample(s,&min,&max);
- if(min<0)
- min = -min;
- if(min>max)
- max = min;
- del = 2*max;
- min = -max;
-
- if(del == 0)
- return;
- sptr = s->data;
- n = s->nsamples;
- while(n--) {
- *sptr = ((((unsigned long)(*sptr-min))*64000)/del)-32000;
- sptr++;
- }
- }
-
- float rmssample(s)
- sample *s;
- {
- }
-
- minmaxsample(s,min,max)
- sample *s;
- int *min, *max;
- {
- int n, smin, smax;
- short *sptr;
-
- sptr = s->data;
- n = s->nsamples;
- smin = 40000;
- smax = -40000;
- while(n--) {
- if(*sptr>smax)
- smax = *sptr;
- if(*sptr<smin)
- smin = *sptr;
- sptr++;
- }
- *min = smin;
- *max = smax;
- }
-
- scalesample(s,gain)
- sample *s;
- float gain;
- {
- int val, n;
- short *sptr;
-
- sptr = s->data;
- n = s->nsamples;
- while(n--) {
- val = (*sptr * gain)+0.5;
- if(val<-32000)
- val = -32000;
- if(val>32000)
- val = 32000;
- *sptr++ = val;
- }
- }
-
- float flerp();
-
- stereoizesample(s,mag)
- sample *s;
- float mag;
- {
- int nsamples;
- int nframes;
- float r, l, m;
- short *sptr;
-
- nframes = s->nsamples/2;
- sptr = s->data;
- while(nframes--) {
- r = sptr[0];
- l = sptr[1];
- m = (r+l)/2.0;
- r = flerp(m,r,mag);
- l = flerp(m,l,mag);
- if(r<-32768) r = -32768;
- if(r> 32767) r = 32767;
- if(l<-32768) l = -32768;
- if(l> 32767) l = 32767;
- sptr[0] = r;
- sptr[1] = l;
- sptr+=2;
- }
- }
-
- freesample(s)
- sample *s;
- {
- free(s->data);
- free(s);
- }
-
- sample *clonesample(s)
- sample *s;
- {
- sample *cs;
-
- cs = (sample *)malloc(sizeof(struct sample));
- *cs = *s;
- cs->data = (short *)malloc(s->nsamples*sizeof(short));
- bcopy(s->data,cs->data,s->nsamples*sizeof(short));
- return cs;
- }
-
- sample *tonesample(nsamples)
- int nsamples;
- {
- sample *s;
- short *sptr, val;
- int i, frames;
-
- if(nsamples&1)
- nsamples--;
- s = (sample *)malloc(sizeof(struct sample));
- s->samprate = 32000;
- s->nchannels = 2;
- s->sampwidth = 2;
- s->nsamples = nsamples;
- s->data = (short *)malloc(s->nsamples*sizeof(short));
- sptr = s->data;
- frames = nsamples/2;
- for(i=0; i<frames; i++) {
- val = 32000.0*sin(2.0*M_PI*i/frames);
- *sptr++ = val;
- *sptr++ = val;
- }
- return s;
- }
-
- sample *subsample(s,begin,end)
- sample *s;
- int begin, end;
- {
- int temp, len;
- sample *cs;
-
- begin = ilimit(0,begin,s->nsamples-1);
- end = ilimit(0,end,s->nsamples-1);
- begin &= 0xffffffe;
- end &= 0xffffffe;
- if(end<begin) {
- temp = end;
- end = begin;
- begin = temp;
- }
- len = end-begin+1;
- cs = (sample *)malloc(sizeof(struct sample));
- *cs = *s;
- cs->nsamples = len;
- cs->data = (short *)malloc(len*sizeof(short));
- bcopy(s->data+begin,cs->data,len*sizeof(short));
- return cs;
- }
-
- sample *extendsample(s,len)
- sample *s;
- int len;
- {
- sample *cs;
-
- cs = (sample *)malloc(sizeof(struct sample));
- *cs = *s;
- cs->nsamples = len;
- cs->data = (short *)malloc(len*sizeof(short));
- bzero(cs->data,len*sizeof(short));
- if(s->nsamples<len)
- len = s->nsamples;
- bcopy(s->data,cs->data,len*sizeof(short));
- return cs;
- }
-
- reversesample(s)
- sample *s;
- {
- int i, nframes;
- short *sptr, *dptr, t;
-
- nframes = s->nsamples/s->nchannels;
- sptr = s->data;
- dptr = s->data+s->nchannels*nframes;
- while(sptr<dptr) {
- dptr -= s->nchannels;
- for(i=0; i<s->nchannels; i++) {
- t = sptr[i];
- sptr[i] = dptr[i];
- dptr[i] = t;
- }
- sptr += s->nchannels;
- }
-
- }
-
- sample *addsample(s1,s2,offset)
- sample *s1, *s2;
- int offset;
- {
- #ifdef NOTDEF
- int nsamples;
- int min, max
- sample *as;
- short *aptr, *bptr, *sptr;
- short p1, p2, s;
- short v1, v2, s;
-
- if(offset<0) {
- min = 0;
- } else {
- min = offset;
- }
- max = MAX(s1->nsamples,s2->nsamples+offset);
- nsamples = max-min;
- as = (sample *)malloc(sizeof(struct sample));
- *as = *s1;
- as->nsamples = nsamples;
- as->data = (short *)malloc(nsamples*sizeof(short));
- for(i=min; i<max; i++) {
- p1 =
- if(i<0
- a = s1
- }
- #endif
- }
-
- /* XXX graphic equalizer someday*/
-
- /*
- * support for playing simultaneous notes follows
- *
- */
- dprintf()
- {
- }
-
- static int curtime = 0;
-
- typedef struct activesample {
- struct activesample *next;
- sample *s;
- int tmin;
- int tmax;
- float amplitude;
- } activesample;
-
- #define CHUNKSIZE (1000)
- #define FOREVER (1000000000)
-
- static activesample *active;
- static float *fbuf;
- static short *sbuf;
- static float bpm = 120.0;
- static float humanamp = 0.0;
- static float humantime = 0.0;
-
- beginnotes()
- {
- curtime = 0;
- active = 0;
- }
-
- endnotes()
- {
- flushnotes(1000000.0);
- flushsample();
- }
-
- setbpm(b)
- float b;
- {
- bpm = b;
- }
-
- sethumanize(t,a)
- float t, a;
- {
- humantime = t;
- humanamp = a;
- }
-
- float frand();
-
- playnote(s,ftime,amplitude)
- sample *s;
- float ftime;
- float amplitude;
- {
- activesample *as;
- int time;
-
- ftime = ftime+(humantime*(frand()-0.5));
- time = ftime*(60.0/bpm)*s->samprate;
- if(time<0.0)
- time = 0.0;
- if(time<curtime) {
- fprintf(stderr,"putsample: start times must be increasing\n");
- fprintf(stderr,"time is %d, curtime is %d\n",time,curtime);
- return;
- }
- as = (activesample *)malloc(sizeof(activesample));
- as->s = s;
- as->tmin = time;
- as->tmax = time+(s->nsamples/2);
- as->amplitude = amplitude*(1.0-humanamp*frand());
-
- /* add the sample to the active list */
- as->next = active;
- active = as;
- }
-
- flushnotes(ftime)
- float ftime;
- {
- int time;
- activesample *as, *temp;
- int mint, nplay, thistime, n;
- int div, val;
- short *sptr;
- float *fptr;
- float amp;
-
- if(!active)
- return;
- time = ftime*(60.0/bpm)*active->s->samprate;
- time -= CHUNKSIZE; /* XXXXX */
- if(!sbuf) {
- fbuf = (float *)malloc(2*CHUNKSIZE*sizeof(float));
- sbuf = (short *)malloc(2*CHUNKSIZE*sizeof(short));
- }
- dprintf("A curtime %d\n",curtime);
- while(active && curtime<time) {
-
- /* figure out how many samples we can put out before change in samples */
- mint = FOREVER;
- as = active;
- while(as) {
- if(curtime<as->tmin) {
- if(mint>as->tmin)
- mint = as->tmin;
- } else if(curtime<as->tmax) {
- if(mint>as->tmax)
- mint = as->tmax;
- }
- as = as->next;
- }
- nplay = mint - curtime;
- if(nplay>CHUNKSIZE)
- nplay = CHUNKSIZE;
-
- /* clear the accumulator */
- bzero(fbuf,2*nplay*sizeof(float));
-
- /* accumulate the active samples */
- div = 0;
- as = active;
- while(as) {
- if((as->tmin<curtime+nplay) && (as->tmax>curtime)) {
- fptr = fbuf;
- sptr = as->s->data+2*(curtime-as->tmin);
- amp = as->amplitude;
- n = 2*nplay;
- while(n--) {
- *fptr = *fptr + amp*(*sptr++);
- fptr++;
- }
- div++;
- }
- as = as->next;
- }
-
- /* copy and range check */
- fptr = fbuf;
- sptr = sbuf;
- n = 2*nplay;
- while(n--) {
- val = *fptr++;
- if(val<-32000)
- *sptr++ = -32000;
- else if(val>32000)
- *sptr++ = 32000;
- else
- *sptr++ = val;
- }
-
- /* play the sum of the active samples */
- writeaudio(sbuf,2*nplay,active->s->samprate);
-
- /* update the time */
- curtime += nplay;
-
- /* remove old samples */
- for( as = (activesample *)&active; as->next; ) {
- if (as->next->tmax <= curtime) {
- temp = as->next;
- as->next = temp->next;
- free(temp);
- } else
- as = as->next;
- }
- }
- }
-